﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using NHibernate;
using RushTracker.Core.Models;
using NHibernate.Criterion;
using Castle.Facilities.NHibernateIntegration;
using NHibernate.Cfg;
using RushTracker.Core.Models.Torrents;
using System.IO;

namespace RushTracker.Core.Data
{
    public class NHibernateDataRepository : IDataRepository
    {
        private ISessionManager _sessionManager;

        public NHibernateDataRepository(ISessionManager sessionManager, Configuration cfg)
        {
            using (StreamReader reader = new StreamReader("C:\\rtdb.txt"))
            {
                string contents = reader.ReadToEnd().Replace("\r", "");
                string[] lines = contents.Split('\n');

                cfg.Properties["connection.connection_string"] = String.Format(cfg.Properties["connection.connection_string"], lines[0], lines[1], lines[2], lines[3]);

                reader.Close();
            }

            this._sessionManager = sessionManager;
        }

        public T GetObjectById<T>(int id)
        {
            return this._sessionManager.OpenSession().Load<T>(id);
        }

        public IList<T> GetAll<T>()
        {
            ICriteria crit = this._sessionManager.OpenSession().CreateCriteria(typeof(T));

            return crit.List<T>();
        }

        public User GetUserByKey(string key)
        {
            ICriteria crit = this._sessionManager.OpenSession().CreateCriteria<User>();
            crit.Add(Expression.Eq("Key", key));
            crit.SetMaxResults(1);

            return crit.UniqueResult<User>();
        }

        public User GetUserByUsername(string username)
        {
            ICriteria crit = this._sessionManager.OpenSession().CreateCriteria<User>();
            crit.Add(Expression.Eq("Username", username));
            crit.SetMaxResults(1);

            return crit.UniqueResult<User>();
        }

        public User GetUserByUsernameAndPassword(string username, string password)
        {
            ICriteria crit = this._sessionManager.OpenSession().CreateCriteria<User>();
            crit.Add(Expression.Eq("Username", username));
            crit.Add(Expression.Eq("Password", password));
            crit.SetMaxResults(1);

            return crit.UniqueResult<User>();
        }

        public Torrent GetTorrentByInfoHash(string infoHash)
        {
            ICriteria crit = this._sessionManager.OpenSession().CreateCriteria<Information>();
            crit.Add(Expression.Eq("InfoHash", infoHash));

            Information info = crit.UniqueResult<Information>();

            if (info == null)
            {
                return null;
            }

            return info.Torrent;
        }

        public Peer GetPeerByInfoHashAndPeerId(string infoHash, string peerId)
        {
            string hql = "from Peer p where p.Information.InfoHash = '" + infoHash + "' and p.PeerId = '" + peerId + "'";
            IQuery query = this._sessionManager.OpenSession().CreateQuery(hql);

            return query.UniqueResult<Peer>();
        }

        public IList<Torrent> GetLatestTorrents(int rows, int? categoryId)
        {
            if (categoryId.HasValue)
                throw new NotImplementedException("GetLatestTorrents for category not implemented");

            string hql = "from Torrent t order by t.Information.CreationDate desc";
            IQuery query = this._sessionManager.OpenSession().CreateQuery(hql);
          
            return query.SetMaxResults(rows).List<Torrent>();
        }

        public IList<Category> GetTopLevelCategories()
        {
            string hql = "from Category c where c.Parent is null";
            IQuery query = this._sessionManager.OpenSession().CreateQuery(hql);

            return query.List<Category>();
        }

        public void SaveObject(object o)
        {
            this._sessionManager.OpenSession().Save(o);
        }

        public void UpdateObject(object o)
        {
            this._sessionManager.OpenSession().Update(o);
        }

        public void DeleteObject(object o)
        {
            this._sessionManager.OpenSession().Delete(o);
        }

        public void Flush()
        {
            this._sessionManager.OpenSession().Flush();
        }
    }
}
